//
//  GKManHistoryData.swift
//  MySwiftObject
//
//  Created by anscen on 2022/1/18.
//  Copyright © 2022 wangws1990. All rights reserved.
//
//
import UIKit
import SQLite.Swift
private let ManTable       = "ManHistoryTable"

private let id             = Expression<String>("comicId")
private let chapter        = Expression<Int>("chapter")
private let pageIndex      = Expression<Int>("pageIndex")
private let insertTime     = Expression<TimeInterval>("insertTime")
private let updateTime     = Expression<TimeInterval>("updateTime")
private let chapterData    = Expression<String?>("chapters")
private let comicData      = Expression<String?>("comicInfo")

class GKManHistoryData{
    fileprivate static var table: Table? = {
        guard let db = dataBase.db else { return nil }
        let tables = Table(ManTable)
        guard let _ = try? db.run(tables.create(ifNotExists: true, block: { (table) in
            //注意.autoincrement
            table.column(id,primaryKey: true)
            table.column(chapter)
            table.column(pageIndex)
            table.column(insertTime)
            table.column(updateTime)
            
            table.column(chapterData)
            table.column(comicData)
        })) else { return nil }
        return tables
    }()
    private static func selectCount(tableName :String,primaryId :String) ->Int{
        guard let db = dataBase.db else { return 0 }
        guard let tb = table else { return 0 }
        let alice = tb.filter(id == primaryId)
        guard let count = try? db.scalar(alice.count) else { return 0 }
        return count
    }
    public static func haveData(_ bookId :String) -> Bool{
        let count = selectCount(tableName: ManTable, primaryId: bookId)
        return count  > 0 ? true : false
    }
}
extension GKManHistoryData{
    public static func insertData(comicId :String,
                                  chap    :Int,
                                  page    :Int,
                                  info    :String?,
                                  chapInfo :String?,
                                  completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let tb = table else { return completion(false) }
        let count = haveData(comicId)
        if !count{
            let time = Date().timeIntervalSince1970
            let insertdata = tb.insert(id <- comicId,
                                          chapter <- chap,
                                          pageIndex <- page,
                                          insertTime <- time,
                                          updateTime <- time,
                                          comicData <- info ?? "",
                                          chapterData <- chapInfo ?? "")
            guard let _ = try? db.run(insertdata) else { return completion(false)}
            completion(true)
        }
    }
    public static func updateChapInfo(comicId   :String,
                                      chapInfo  :String,
                                      completion:@escaping ((_ success : Bool) -> ())){
        if haveData(comicId){
            guard let tb = table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(comicId == id)
            let update = run.update(id <- comicId,chapterData <- chapInfo,updateTime <- time)
            runUpdate(update, completion: completion)
        }else{
            insertData(comicId: comicId, chap: 0, page: 0, info: nil,chapInfo: chapInfo, completion: completion)
        }
    }
    public static func updateComic(comicId :String,info:String,completion:@escaping ((_ success : Bool) -> ())){
        if haveData(comicId){
            guard let tb = table else { return completion(false) }
            let time = Date().timeIntervalSince1970
            let run = tb.filter(comicId == id)
            let update = run.update(id <- comicId,comicData <- info,updateTime <- time)
            runUpdate(update, completion: completion)
        }else{
            insertData(comicId: comicId, chap: 0, page: 0, info: info,chapInfo: nil, completion: completion)
        }
    }
    public static func  updateChapterIndex(comicId :String,chap :Int,page :Int,completion:@escaping ((_ success : Bool) -> ())){
        if haveData(comicId){
            let time = Date().timeIntervalSince1970
            guard let tb = table else { return completion(false) }
            let run = tb.filter(comicId == id)
            let update = run.update(id <- comicId,insertTime <- time,chapter <- chap,pageIndex <- page)
            runUpdate(update, completion: completion)
        }else{
            insertData(comicId: comicId, chap: chap, page: page, info: nil,chapInfo: nil, completion: completion)
        }
    }

    public static func deleteData(comicId :String,completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let tb = table else { return completion(false) }
        let alice = tb.filter(id == comicId)
        guard let _ = try? db.run(alice.delete()) else { return completion(false) }
        completion(true)
    }
    public static func getData(comicId :String,needChapter :Bool,completion:@escaping ((_ model : GKManHistory?) -> ())){
        guard let db = dataBase.db else { return completion(nil) }
        guard let tb = table else { return completion(nil) }
        let alice = tb.filter(id == comicId)
        guard let datas : AnySequence<Row> = try? db.prepare(alice) else {
            return completion(nil)
        }
        let objc = datas.first { row in
            return String(row[id]).count > 0
        }
        guard let row = objc else {
            return completion(nil)
        }
        let his = decode(objc: row, needChapter: needChapter)
        completion(his)
    }
    public class func getData(completion:@escaping ((_ datas : [GKManHistory]) ->())){
        guard let db = dataBase.db else { return completion([]) }
        guard let tb = table else { return completion([]) }
        guard let datas : AnySequence<Row> = try? db.prepare(tb) else {
            return completion([])
        }
        decodeData(listData: datas,needChapter: false,completion: completion)
    }
    private class func decodeData(listData : AnySequence<Row>,needChapter :Bool = false,completion:@escaping ((_ datas : [GKManHistory]) ->())){
        DispatchQueue.global().async {
            var content : [GKManHistory] = []
            listData.forEach { (objc) in
                if let model = decode(objc: objc, needChapter: needChapter){
                    content.append(model)
                }
            }
            DispatchQueue.main.async {
                completion(content)
            }
        }
    }
    private class func decode(objc : Row,needChapter :Bool) -> GKManHistory?{
        let  model =  GKManHistory()
        if let bookId = try? objc.get(id) {
            model.comicId = bookId
        }
        if let chap = try? objc.get(chapter) {
            model.chapter = chap
        }
        if let page = try? objc.get(pageIndex) {
            model.pageIndex = page
        }
        if let time = try? objc.get(insertTime){
            model.insertTime =  TimeInterval(time)
        }
        if let time = try? objc.get(updateTime){
            model.updateTime =  TimeInterval(time)
        }
//        if let json = try? objc.get(comicData) {
//            let bookJson = JSON(parseJSON:json)
//            let info = GKBook.deserialize(from: bookJson.rawString())
//            model.book = info
//        }
        if let str = try? objc.get(chapterData) {
            if needChapter {
                let json = JSON(parseJSON: str)
                let data = [GKManChapter].deserialize(from: json.rawString())
                if let listData = data as? [GKManChapter] {
                    model.chapters = listData
                }
            }
        }
        return model
    }
    fileprivate class func runUpdate(_ task :Update,completion:@escaping ((_ success : Bool) -> ())){
        guard let db = dataBase.db else { return completion(false) }
        guard let _ = try? db.run(task) else { return completion(false) }
        completion(true)
    }
}
